/*
 *  Copyright (c) 1998, Regents of the University of California
 *  All rights reserved.
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 * 
 *      * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *      * Neither the name of the University of California, Berkeley nor the
 *        names of its contributors may be used to endorse or promote products
 *        derived from this software without specific prior written permission.
 * 
 *  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
 *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 *  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.demis.elf;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Description of a database table.
 * @version 1.0
 * @author <a href="mailto:demis27@demis27.net">Stéphane kermabon</a>
 */
public class Table {

    private int positionForNotposionedColumn = 100;
    
    private final Log logger = LogFactory.getLog(Table.class);
    /** Name of the column. */
    private String name = null;
    /** Primary key of this table. */
    private PrimaryKey primaryKey = null;
    
    private Map<String, ForeignKey> importedKeys = new HashMap<String, ForeignKey>();
    
    private Map<String, ForeignKey> exportedKeys = new HashMap<String, ForeignKey>();
    /** Sorted set of columns. */
    private Set<Column> columns = new TreeSet<Column>();
    /** List of unique constraint for this table. */
    private Map<String, UniqueConstraint> uniqueConstraints = new HashMap<String, UniqueConstraint>();
    /** Remarks on this table. */
    private String remarks = null;
    /** Schema that contains this table. */
    private Schema schema = null;
    /** List of index on this table. */
    private Map<String, Index> indexes = new HashMap<String, Index>();

    private List<DataLine> lines = new ArrayList<DataLine>();

    public Table() {
        // no op
    }
    
    public Table(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void addColumn(Column column) {
        if (column.getPosition() < 1) {
            column.setPosition(positionForNotposionedColumn++);
        }
        columns.add(column);
        column.setTable(this);
    }
    
    public List<Column> getColumns() {
        return new ArrayList(columns);
    }

    public Column getColumn(int position) {
        if (position <= columns.size() && position > 0) {
            return ((Column[])columns.toArray())[position - 1];
        }
        return null;
    }

    public Column getColumn(String columnName) {
        for (Column column : columns) {
            if (column.getName() != null && column.getName().equals(columnName)) {
                return column;
            }
        }
        return null;
    }

    public PrimaryKey getPrimaryKey() {
        return primaryKey;
    }

    public void setPrimaryKey(PrimaryKey primaryKey) {
        if (this.primaryKey != primaryKey) {
            this.primaryKey = primaryKey;
            primaryKey.setTable(this);
        }
    }
    
    public void addExportedKey(ForeignKey reference) {
        exportedKeys.put(reference.getName(), reference);
    }
    
    public List<ForeignKey> getExportedKeys() {
        return new ArrayList(exportedKeys.values());
    }
    
    public ForeignKey getExportedKey(String toReferenceName) {
        return exportedKeys.get(toReferenceName);
    }
    
    public void addImportedKey(ForeignKey importedKey) {
        importedKeys.put(importedKey.getName(), importedKey);
    }
    
    public List<ForeignKey> getImportedKeys() {
        return new ArrayList(importedKeys.values());
    }
    
    public ForeignKey getImportedKey(String fromReferenceName) {
        return importedKeys.get(fromReferenceName);
    }

    public String getRemarks() {
        return remarks;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }

    public Map<String, ForeignKey> getFromReferencesMap() {
        return importedKeys;
    }

    public Map<String, ForeignKey> getToReferencesMap() {
        return exportedKeys;
    }

    public Schema getSchema() {
        return schema;
    }

    public void setSchema(Schema schema) {
        this.schema = schema;
    }

    public void addIndex(Index index) {
        indexes.put(index.getName(), index);
    }

    public Index getIndex(String indexName) {
        return indexes.get(indexName);
    }

    public List<Index> getIndexes() {
        return new ArrayList(indexes.values());
    }

    public void addUniqueConstraint(UniqueConstraint uniqueConstraint) {
        uniqueConstraints.put(uniqueConstraint.getName(), uniqueConstraint);
    }

    public UniqueConstraint getUniqueConstraint(String uniqueConstraintName) {
        return uniqueConstraints.get(uniqueConstraintName);
    }

    public List<UniqueConstraint> getUniqueConstraints() {
        return new ArrayList(uniqueConstraints.values());
    }

    public List<DataLine> getLines() {
        return lines;
    }

    public void addLine(DataLine line) {
        lines.add(line);

    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Table other = (Table) obj;
        if (this.name != null && this.name.equals(other.name) && 
                (schema == null || schema.getName() == null || schema.getName().equals(other.schema.getName()))) {
            return true;
        }
        return false;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 89 * hash + (this.name != null ? this.name.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString() {
        return name;
    }

}
